<?php
/**
 * RedCross Application
 *
 * @copyright Copyright (c) 2010, Kristian Stokke Tryggestad, Rune Vikestad, Andreas Flaten Wist, Simen Nicolai Echholt, Ole Henrik Jahren
 */


class RedCross_Acl extends Zend_Acl
{
    const GUEST_NAME = 'Gjest';
    const GROUP_PREFIX = 'group:';
    const USER_PREFIX = 'user:';

    protected $_role;
    protected $_authService;

    public function __construct()
    {
        $this->_authService = RedCross_Factory::getService('Core_Service_Auth');

        $this->_addResources();
        $this->_addGroups();

        // Add guest role if it is not already added
        $this->_addGuestRole();

        $this->_addPrivileges();
        $this->_addAssertions();
    }

    protected function _addResources()
    {
        $result = Doctrine_Query::create()
            ->select()
            ->from('RedCross_Gateway_Base_Resource r')
            ->fetchArray();

        foreach ($result as $resource) {
        	$this->addResource($resource['name']);
        }
    }

    protected function _addGroups()
    {
        $result = Doctrine_Query::create()
            ->select()
            ->from('RedCross_Gateway_Base_Group g')
            ->fetchArray();

        foreach ($result as $group) {
        	$this->addRole(self::GROUP_PREFIX . $group['name']);
        }
    }

    protected function _addPrivileges()
    {
        $result = Doctrine_Query::create()
            ->select()
            ->from('RedCross_Gateway_Base_Group g')
            ->leftJoin('g.Privileges p')
            ->leftJoin('p.Resource r')
            ->fetchArray();

        foreach ($result as $group) {
            $privileges = array();
            foreach ($group['Privileges'] as $privilege) {
                $privileges[$privilege['Resource']['name']][] = $privilege['name'];
            }

            foreach ($privileges as $resource => $privileges) {
            	$this->allow(self::GROUP_PREFIX . $group['name'], $resource, $privileges);
//            	echo $group['name'] . ' was allowed to access ' . $resource . ' with privilege ' . implode(', ', $privileges);
            }
        }
    }

    protected function _addGuestRole()
    {
        if ($this->hasRole(self::GUEST_NAME)) {
            return;
        }
        if (!$this->hasRole(self::GROUP_PREFIX . self::GUEST_NAME)) {
            $guest = new Zend_Acl_Role(self::GUEST_NAME);
        	$this->addRole($guest);
        	$this->deny($guest, null, null);
        } else {
            $guest = new Zend_Acl_Role(self::GUEST_NAME);
        	$this->addRole($guest, self::GROUP_PREFIX . self::GUEST_NAME);
        }
    }

    protected function _addAssertions()
    {
        $this->addResource('model:shift');
        $this->allow(null, 'model:shift', array('replaceRole'), new RedCross_Acl_Assert_IsShiftLeader());
    }

    public function initRole()
    {
        if (!$this->_authService->isAuthenticated()) {
        	$this->setRole();
            return;
        }
        $identity = $this->_authService->getIdentity();

        if ($this->hasRole(self::USER_PREFIX . $identity->username)) {
        	return;
        }

        $query = Doctrine_Query::create()
            ->select('u.username, g.name')
            ->from('Core_Model_User u')
            ->leftJoin('u.Groups g')
            ->where('u.id = ?', $identity->id);

        $manager = Doctrine_Manager::getInstance();
        if(!is_null($manager->getAttribute(Doctrine_Core::ATTR_RESULT_CACHE))) {
             // Enable result cache of this query
            $query->setResultCacheLifeSpan(60 * 10)
                ->useResultCache(true);
        }

        $result = $query->fetchOne();

        // Build an array of groups that the ACL can handle
        $groups = array();
        foreach ($result->Groups as $group) {
        	$groups[] = self::GROUP_PREFIX . $group->name;
        }

        $this->addRole($result, $groups);
        $this->setRole($result);
    }

    private function setRole(Zend_Acl_Role_Interface $role = null)
    {
	    if ($role instanceof Core_Model_User && isset($role->id)) {
	        $this->_role = $role;
	    } else {
	        $this->_role = new Zend_Acl_Role(self::GUEST_NAME);
	    }
	    RedCross_Factory::setRole($this);
    }

    public function retrieveRole()
    {
	    return $this->_role;
    }

    public function getParentsForRole()
    {
        return $this->_getRoleRegistry()->getParents($this->_role);
    }
}